#include "utils_stack_trace.h"
#include <array>
#include <execinfo.h>
#include <cxxabi.h>
#include <dlfcn.h>
#include <cstdio>
#include <sstream>
#include <csignal>
#include <unistd.h>
#include <cstring>

namespace El {
namespace Utils {

namespace {
// 需要处理的信号列表
const std::array<int, 6> SIGNALS_TO_HANDLE = {
    SIGSEGV, // 段错误
    SIGABRT, // 异常终止
    SIGFPE,  // 浮点异常
    SIGILL,  // 非法指令
    SIGBUS,  // 总线错误
    SIGTRAP  // 断点陷阱
};

// 原始的信号处理函数
std::array<struct sigaction, SIGNALS_TO_HANDLE.size()> g_old_actions;

// 获取信号描述
const char* GetSignalDescription(int signo) {
    switch (signo) {
        case SIGSEGV: return "Segmentation fault";
        case SIGABRT: return "Aborted";
        case SIGFPE:  return "Floating point exception";
        case SIGILL:  return "Illegal instruction";
        case SIGBUS:  return "Bus error";
        case SIGTRAP: return "Trace/breakpoint trap";
        default:      return "Unknown signal";
    }
}
} // namespace

StackTrace &StackTrace::GetInstance()
{
    static StackTrace instance;
    return instance;
}

StackTrace::~StackTrace()
{
    if (initialized_) {
        // 恢复原始的信号处理函数
        for (size_t i = 0; i < SIGNALS_TO_HANDLE.size(); ++i) {
            sigaction(SIGNALS_TO_HANDLE[i], &g_old_actions[i], nullptr);
        }
    }
}

bool StackTrace::Start(bool enable_signal_handler)
{
    if (initialized_) {
        return true;
    }

    if (enable_signal_handler) {
        struct sigaction action;
        action.sa_handler = SignalHandler;
        sigemptyset(&action.sa_mask);
        action.sa_flags = SA_RESETHAND; // 处理完信号后恢复默认处理

        // 设置信号处理函数
        for (size_t i = 0; i < SIGNALS_TO_HANDLE.size(); ++i) {
            if (sigaction(SIGNALS_TO_HANDLE[i], &action, &g_old_actions[i]) != 0) {
                fprintf(stderr, "Failed to set signal handler for signal %d\n", SIGNALS_TO_HANDLE[i]);
                return false;
            }
        }
    }

    initialized_ = true;
    return true;
}

void StackTrace::SignalHandler(int signo)
{
    // 确保信号处理过程中不会被其他信号打断
    for (int sig : SIGNALS_TO_HANDLE) {
        signal(sig, SIG_DFL);
    }

    char prog_name[256];
    ssize_t len = readlink("/proc/self/exe", prog_name, sizeof(prog_name) - 1);
    if (len != -1) {
        prog_name[len] = '\0';
    } else {
        std::strcpy(prog_name, "unknown");
    }

    fprintf(stderr, "\n*** Crash Report ***\n");
    fprintf(stderr, "Program: %s\n", prog_name);
    fprintf(stderr, "PID: %d\n", getpid());
    fprintf(stderr, "Signal: %d (%s)\n", signo, GetSignalDescription(signo));
    
    // 打印堆栈信息
    GetInstance().PrintStackTrace();

    // 调用用户定义的回调函数
    if (GetInstance().crash_callback_) {
        GetInstance().crash_callback_();
    }

    // 打印内存映射信息
    FILE* maps = fopen("/proc/self/maps", "r");
    if (maps) {
        char line[1024];
        fprintf(stderr, "\nMemory map:\n");
        while (fgets(line, sizeof(line), maps)) {
            fprintf(stderr, "%s", line);
        }
        fclose(maps);
    }

    // 刷新输出缓冲区
    fflush(stderr);

    // 向自己发送信号以确保程序终止
    kill(getpid(), signo);
}

std::string StackTrace::GetFrameInfo(void *addr)
{
    std::ostringstream oss;
    Dl_info info;

    if (dladdr(addr, &info)) {
        const char *symbol = info.dli_sname;
        if (symbol != nullptr) {
            int status;
            char *demangled = abi::__cxa_demangle(symbol, nullptr, nullptr, &status);
            if (status == 0 && demangled) {
                oss << info.dli_fname << "(" << demangled << "+0x" << std::hex << (char *)addr - (char *)info.dli_saddr
                    << ")";
                free(demangled);
            } else {
                oss << info.dli_fname << "(" << symbol << "+0x" << std::hex << (char *)addr - (char *)info.dli_saddr
                    << ")";
            }
        } else {
            oss << info.dli_fname << "(0x" << std::hex << (char *)addr - (char *)info.dli_fbase << ")";
        }
    } else {
        oss << "(unknown)";
    }

    oss << " [" << addr << "]";
    return oss.str();
}

std::string StackTrace::GetStackTrace(int skip_frames)
{
    std::array<void*, MAX_STACK_FRAMES> stack;
    int frames = backtrace(stack.data(), stack.size());

    std::ostringstream oss;
    oss << "Stack trace (" << frames << " frames):\n";

    // 跳过指定数量的栈帧
    for (int i = skip_frames; i < frames; ++i) {
        oss << "#" << (i - skip_frames) << ": " << GetFrameInfo(stack[i]) << "\n";
    }

    return oss.str();
}

void StackTrace::PrintStackTrace()
{
    fprintf(stderr, "%s", GetStackTrace(1).c_str());
}

void StackTrace::SetCrashCallback(std::function<void()> callback)
{
    crash_callback_ = std::move(callback);
}

} // namespace Utils
} // namespace El